/*
 * This program is free software; you can redistribute it and/or modify it under the 
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software 
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this 
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 
 * or from the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * Copyright 2008 Pentaho Corporation.  All rights reserved.
 *
 * @author Will Gorman (wgorman@pentaho.com)
 */
package org.pentaho.actioneditor.client;

import java.util.MissingResourceException;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.pentaho.actioneditor.client.actionpanels.IActionPanel;
import org.pentaho.actioneditor.client.actionpanels.JFreeReportActionPanel;
import org.pentaho.actioneditor.client.actionpanels.SqlQueryActionPanel;
import org.pentaho.actioneditor.client.processpanels.InputPanel;
import org.pentaho.actioneditor.client.processpanels.OutputPanel;
import org.pentaho.actioneditor.client.processpanels.ResourcePanel;
import org.pentaho.actionsequence.dom.ActionSequenceDocument;
import org.pentaho.actionsequence.dom.ActionSequenceInput;
import org.pentaho.actionsequence.dom.IActionDefinition;
import org.pentaho.actionsequence.dom.IActionSequenceExecutableStatement;
import org.pentaho.actionsequence.dom.IActionSequenceInput;
import org.pentaho.actionsequence.dom.IActionSequenceOutput;
import org.pentaho.actionsequence.dom.IActionSequenceResource;
import org.pentaho.actionsequence.dom.actions.JFreeReportAction;
import org.pentaho.actionsequence.dom.actions.SqlQueryAction;
import org.pentaho.actionsequence.dom.gwtimpl.URI;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.client.Dictionary;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.HistoryListener;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SourcesTabEvents;
import com.google.gwt.user.client.ui.TabListener;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.TreeListener;
import com.google.gwt.user.client.ui.Widget;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class ActionEditor implements EntryPoint, HistoryListener {

  final ActionEditorUI ui = new ActionEditorUI();
  
  static final String SERVICE_LOCATION = "/ActionEditorService"; 
  
  ActionSequenceDocument actionSequenceDocument = null;
  String actionSequence = null;
  
  
  public String getOutputType(String outputName) {
    IActionSequenceInput inputs[] = actionSequenceDocument.getInputs();
    for (int i = 0; i < inputs.length; i++) {
      if (inputs[i].getName().equals(outputName)) {
        return inputs[i].getType();
      }
    }
    IActionSequenceExecutableStatement actions[] = actionSequenceDocument.getExecutableChildren();
    for (int i = 0; i < actions.length; i++) {
      if (actions[i] instanceof IActionDefinition) {
        IActionDefinition def = (IActionDefinition)actions[i];
        for (int j = 0; j < def.getOutputs().length; j++) {
          if (def.getOutputs()[j].getPublicName().equals(outputName)) {
            return def.getOutputs()[j].getType();
          }
        }
      }
    }
    return null;
  }
  
  public void updateOutputMenuBar() {
    ui.getAddOutputMenuBar().clearItems();
    IActionSequenceInput inputs[] = actionSequenceDocument.getInputs();
    for (int i = 0; i < inputs.length; i++) {
      // add to input  to output add also
      MenuItem item = new MenuItem(inputs[i].getName(), (Command)null);
      item.setCommand(ui.addOutputCommandHelper.getCommand(item));
      ui.getAddOutputMenuBar().addItem(item);
    }
    IActionSequenceExecutableStatement actions[] = actionSequenceDocument.getExecutableChildren();
    for (int i = 0; i < actions.length; i++) {
      if (actions[i] instanceof IActionDefinition) {
        IActionDefinition def = (IActionDefinition)actions[i];
        for (int j = 0; j < def.getOutputs().length; j++) {
          // add output params to output add also
          MenuItem menuitem = new MenuItem(def.getOutputs()[j].getPublicName(), (Command)null);
          menuitem.setCommand(ui.addOutputCommandHelper.getCommand(menuitem));
          ui.getAddOutputMenuBar().addItem(menuitem);
        }
      } else {
        System.out.println("WARNING, UNKNOWN EXEC: " + actions[i]);
      }
    }
  }
  
  public void syncFromXMLToProcess() {
    // write to the three display categories
    Document d = null;
    try {
      d = DocumentHelper.parseText(ui.getXml().getText());
      actionSequenceDocument = new ActionSequenceDocument(d);
      IActionSequenceInput inputs[] = actionSequenceDocument.getInputs();
      ui.getInputTreeInputs().removeItems();
      for (int i = 0; i < inputs.length; i++) {
        ui.getInputTreeInputs().addItem(inputs[i].getName() +" (" + inputs[i].getType() + ")");
      }
      
      IActionSequenceResource resources[] = actionSequenceDocument.getResources();
      ui.getInputTreeResources().removeItems();
      for (int i = 0; i < resources.length; i++) {
        ui.getInputTreeResources().addItem(resources[i].getName());
      }
      
      IActionSequenceExecutableStatement actions[] = actionSequenceDocument.getExecutableChildren();
      ui.getProcessTree().removeItems();
      for (int i = 0; i < actions.length; i++) {
        if (actions[i] instanceof IActionDefinition) {
          IActionDefinition def = (IActionDefinition)actions[i];
          TreeItem item = new TreeItem(getTitle(def));
          for (int j = 0; j < def.getOutputs().length; j++) {
            item.addItem(def.getOutputs()[j].getPublicName());
          }
          ui.getProcessTree().addItem(item);
        } else {
          System.out.println("WARNING, UNKNOWN EXEC: " + actions[i]);
          ui.getProcessTree().addItem(actions[i].toString());
        }
      }

      updateOutputMenuBar();
      
      ui.getOutputTree().getItem(0).removeItems();
      IActionSequenceOutput outputs[] = actionSequenceDocument.getOutputs();
      for (int i = 0; i < outputs.length; i++) {
        ui.getOutputTree().getItem(0).addItem(outputs[i].getName());
      }
      

      
    } catch (Exception e) {
      e.printStackTrace();
    }
    
    ui.getDetailsPanel().clear();
     
  }
  
  public static String getTitle(IActionDefinition actionDefinition) {
    String text = actionDefinition.getDescription();
    if (text.length() == 0) {
      text = actionDefinition.getComponentName().trim();
      if ((text != null) && (text.length() > 0)) {
        int index = text.lastIndexOf("."); //$NON-NLS-1$
        if ((index >= 0) && ((index + 1) < text.length()))
        {
          String subStr = text.substring(index + 1).trim();
          if (subStr.length() > 0)
          {
            text = subStr;
          }
        }
      }
    }
    if ((text == null) || (text.length() == 0)) {
      text = "Unknown Text";
    }
    return text;
  }
  
  public void syncFromProcessToXML() {
    // the actionSequenceDocument should already be in sync
    ui.getXml().setText(actionSequenceDocument.toString());
  }
  
  public void syncFromGeneralToXML() {
    Document d = null;
    try {
      d = DocumentHelper.parseText(ui.getXml().getText());
      actionSequenceDocument = new ActionSequenceDocument(d);
      actionSequenceDocument.setTitle(ui.getTitle().getText());    
      actionSequenceDocument.setVersion(ui.getVersion().getText());
      actionSequenceDocument.setLoggingLevel(ui.getLoggingLevel().getItemText(ui.getLoggingLevel().getSelectedIndex()));
      actionSequenceDocument.setAuthor(ui.getAuthor().getText());
      actionSequenceDocument.setResultType(ui.getResultType().getText());
      actionSequenceDocument.setDescription(ui.getDescription().getText());
      actionSequenceDocument.setHelp(ui.getHelp().getText());
      actionSequenceDocument.setIconLocation(ui.getIcon().getText());
    
      ui.getXml().setText(actionSequenceDocument.toString());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  public void syncFromXMLToGeneral() {
    try {
      Document d = DocumentHelper.parseText(ui.getXml().getText());
      populateWidgets(d);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  public void populateWidgets(Document d) {
    actionSequenceDocument = new ActionSequenceDocument(d);
    
    ui.getTitle().setText(actionSequenceDocument.getTitle());
    ui.getVersion().setText(actionSequenceDocument.getVersion());
    String loggingLevel = actionSequenceDocument.getLoggingLevel();
    for (int i = 0; i < ui.getLoggingLevel().getItemCount(); i++) {
      if (ui.getLoggingLevel().getItemText(i).equalsIgnoreCase(loggingLevel)) {
        ui.getLoggingLevel().setItemSelected(i, true);
      }
    }
    
    ui.getAuthor().setText(actionSequenceDocument.getAuthor());
    String resultType = actionSequenceDocument.getResultType();
    ui.getResultType().setText(resultType);
    
    ui.getVisible().setChecked(!"none".equals(resultType));
    
    ui.getIcon().setText(actionSequenceDocument.getIconLocation());
    ui.getDescription().setText(actionSequenceDocument.getDescription());
    ui.getHelp().setText(actionSequenceDocument.getHelp());
  }

  int lastTabIndex = 0;
  
  public static int getItemIndex(Tree tree, TreeItem item) {
    for (int i = 0; i < item.getTree().getItemCount(); i++) {
      if (item == item.getTree().getItem(i)) {
        return i;
      }
    }
    return -1;
  }
  
  /**
   * This is the entry point method.
   */
	public void onModuleLoad() {
    /*
     *  Move this into a utility app for rendering UIs
     * 
    final TabPanel tp = new TabPanel();
    VerticalPanel vp = new VerticalPanel();
    final TextArea ta = new TextArea();
    ta.setVisibleLines(10);
    ta.setCharacterWidth(10);
    ta.setWidth("100%");
    ta.setHeight("100%");
    vp.add(ta);
    HorizontalPanel panel = new HorizontalPanel();
    Button b1 = new Button("Clear");
    b1.addClickListener(new ClickListener() {
        public void onClick(Widget widget) {
          ta.setText("");
        }
    });
    Button b = new Button("Update");
    panel.add(b1);
    panel.add(b);
    vp.add(panel);
    b.addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        ta.getText();
        GWTUIGen gen = new GWTUIGen(ta.getText());
        tp.add((Widget)gen.getWidgetById("root"), "New");
      }
    });
    tp.add(vp, "XML");
    tp.setWidth("100%");
    tp.setHeight("100%");
    RootPanel.get("slot3").add(tp);
    RootPanel.get("slot3").setWidth("100%");
    
    History.addHistoryListener(this);    
    
    if (true) return;
    
    */
    
    // Inputs / Resources
    
    ui.setAddInputCommand(new ActionEditorUI.ItemCommand() {
      public void execute(String text) {
        // add the new item to the tree, "newInputX (type)";
        if ("resource".equals(text)) {
          int max = 0;
          for (int i = 0; i < ui.getInputTreeResources().getChildCount(); i++) {
            TreeItem item = ui.getInputTreeResources().getChild(i);
            if (item.getText().indexOf("newResource") >= 0) {
              max++;
              while (item.getText().indexOf("newResource" + max) >= 0) {
                max++;
              }
            }
          }
          String name = "newResource";
          if (max > 0) {
            name += "" + max;
          }
          try {
            IActionSequenceResource resource = actionSequenceDocument.setResourceUri(name, new URI("solution:", " ", null), "");
            final TreeItem item = ui.getInputTreeResources().addItem(resource.getName());
            if (!ui.getInputTreeResources().getState()) {
              ui.getInputTreeResources().setState(true);
            }
            item.setSelected(true);
            ResourcePanel panel = new ResourcePanel(resource, item);
            panel.init();
            ui.getDetailsPanel().clear();
            ui.getDetailsPanel().add(panel.getRoot());
          } catch (Exception e) {
            e.printStackTrace();
          }
          
        } else {
          int max = 0;
          for (int i = 0; i < ui.getInputTreeInputs().getChildCount(); i++) {
            TreeItem item = ui.getInputTreeInputs().getChild(i);
            if (item.getText().indexOf("newInput") >= 0) {
              max++;
              while (item.getText().indexOf("newInput" + max) >= 0) {
                max++;
              }
            }
          }
          String name = "newInput";
          if (max > 0) {
            name += "" + max;
          }
          
          IActionSequenceInput input = actionSequenceDocument.createInput(name, text);
          
          final TreeItem item = ui.getInputTreeInputs().addItem(input.getName() +" (" + input.getType() + ")");
          if (!ui.getInputTreeInputs().getState()) {
            ui.getInputTreeInputs().setState(true);
          }
          item.setSelected(true);
          InputPanel panel = new InputPanel((ActionSequenceInput)input, ActionEditor.this, item);
          panel.init();
          ui.getDetailsPanel().clear();
          ui.getDetailsPanel().add(panel.getRoot());
        }
        
        //displayDetailsPanel(input, item); // name, text, item);
      }
    });
    
    ui.getInputTree().addTreeListener(new TreeListener() {

      public void onTreeItemSelected(TreeItem item) {
        if (item.getParentItem() == ui.getInputTreeInputs()) {
          String name = item.getText().substring(0, item.getText().indexOf(" ("));
          String type = item.getText().substring(item.getText().indexOf(" (") + 2, item.getText().indexOf(")"));
          IActionSequenceInput input = actionSequenceDocument.getInput(name);
          InputPanel panel = new InputPanel(input, ActionEditor.this, item);
          panel.init();
          ui.getDetailsPanel().clear();
          ui.getDetailsPanel().add(panel.getRoot());
        } else if (item.getParentItem() == ui.getInputTreeResources()) {
          IActionSequenceResource resource = actionSequenceDocument.getResource(item.getText());
          ResourcePanel panel = new ResourcePanel(resource, item);
          panel.init();
          ui.getDetailsPanel().clear();
          ui.getDetailsPanel().add(panel.getRoot());
        }
      }

      public void onTreeItemStateChanged(TreeItem item) {
      }
      
    });
    
    ui.getDeleteInput().setCommand(new Command() {
      public void execute() {
        // delete the item in the tree that is currently selected
        TreeItem item = ui.getInputTree().getSelectedItem();
        if (item != ui.getInputTreeInputs() && item != ui.getInputTreeResources() && item != null) {
          if (item.getParentItem() == ui.getInputTreeInputs()) {
            String name = item.getText().substring(0, item.getText().indexOf(" ("));
            actionSequenceDocument.deleteInput(name);
          } else {
            actionSequenceDocument.deleteResource(item.getText());
          }
          
          ui.getInputTree().setSelectedItem(null);
          item.remove();
          
          ui.getDetailsPanel().clear();
        }
      }
    });

    // Actions
    
    ui.setAddComponentCommand(new ActionEditorUI.ItemCommand() {
      public void execute(String text) {
        ui.getDetailsPanel().clear();        
        IActionDefinition action = createActionDefinition(text);
        if (action != null) {
          TreeItem item = new TreeItem(getTitle(action));
          ui.getProcessTree().addItem(item);
          IActionPanel panel = createActionPanel(action);
          if (panel != null) {
            panel.setTreeItem(item);
            panel.init();
            ui.getDetailsPanel().add(panel.getRoot());
          }
        }
      }
    });
    
    ui.getProcessTree().addTreeListener(new TreeListener() {

      public void onTreeItemSelected(TreeItem item) {
        if (item.getParentItem() == null) {
          ui.getDetailsPanel().clear();
          int index = getItemIndex(item.getTree(), item);
          if (index != -1) {
            IActionSequenceExecutableStatement action = actionSequenceDocument.getExecutableChildren()[index];
            IActionPanel panel = createActionPanel(action);
            if (panel != null) {
              panel.setTreeItem(item);
              panel.init();
              ui.getDetailsPanel().add(panel.getRoot());
            }
          } else {
            System.out.println("error: process tree item not found: " + item.getText());
          }
        }
      }

      public void onTreeItemStateChanged(TreeItem item) {
      }
      
    });
    
    ui.getDeleteComponent().setCommand(new Command() {
      public void execute() {
        // delete the item in the tree that is currently selected
        TreeItem item = ui.getProcessTree().getSelectedItem();
        if (item.getParentItem() == null) {
          int index = getItemIndex(item.getTree(), item);
          if (index != -1) {
            IActionSequenceExecutableStatement action = actionSequenceDocument.getExecutableChildren()[index];
            action.delete();
            item.remove();  
            ui.getDetailsPanel().clear();
          }
        }  
      }
    });
    
    // Outputs
    
    ui.setAddOutputCommand(new ActionEditorUI.ItemCommand() {
      public void execute(String text) {
        // find text's input type
        if (actionSequenceDocument.getOutput(text) != null) {
          // don't add twice, this mimics how we do it in DS
          return;
        }
        
        IActionSequenceOutput output = actionSequenceDocument.createOutput(text, getOutputType(text));
        
        final TreeItem item = ui.getOutputTree().getItem(0).addItem(text);
        if (!ui.getOutputTree().getItem(0).getState()) {
          ui.getOutputTree().getItem(0).setState(true);
        }
        item.setSelected(true);
        
        OutputPanel panel = new OutputPanel(output);
        panel.init();
        ui.getDetailsPanel().clear();
        ui.getDetailsPanel().add(panel.getRoot());
      }
    });
    
    ui.getOutputTree().addTreeListener(new TreeListener() {
      public void onTreeItemSelected(TreeItem item) {
        if (item.getParentItem() != null) {
          IActionSequenceOutput output = actionSequenceDocument.getOutput(item.getText());
          OutputPanel panel = new OutputPanel(output);
          panel.init();
          ui.getDetailsPanel().clear();
          ui.getDetailsPanel().add(panel.getRoot());
        }
      }

      public void onTreeItemStateChanged(TreeItem item) {
      }
    });
    
    ui.getDeleteOutput().setCommand(new Command() {
      public void execute() {
        TreeItem item = ui.getOutputTree().getSelectedItem();
        if (item.getParentItem() != null) {
          actionSequenceDocument.deleteOutput(item.getText());
          item.remove();
          ui.getDetailsPanel().clear();
        }
      }
      
    });
    
    ui.init();
    
    final Label label = new Label();
    
//    Dictionary theme = Dictionary.getDictionary("actionEditorParams");
    
    final String newActionSequence = getRequestParameter("actionSequence");
    if (newActionSequence != null && newActionSequence.trim().length() > 0) {
      actionSequence = newActionSequence;
    } else {
      try {
        
        Dictionary theme = Dictionary.getDictionary("actionEditorParams");
        if (theme != null) {
          actionSequence = theme.get("actionSequence");
        }
      } catch (MissingResourceException e) {
        // ignore exception
        // this may be thrown if the dictionary is not defined.
      }
      if (actionSequence == null) {
        RootPanel.get("actionUrl").add(new Label("No Action Specified"));
        return; 
      }
    }    
    // load the themed actionSeque
    ActionEditorServiceAsync service = (ActionEditorServiceAsync) GWT.create(ActionEditorService.class);
    ServiceDefTarget endpoint = (ServiceDefTarget) service;
    String moduleRelativeURL = GWT.getModuleBaseURL() + SERVICE_LOCATION;
    endpoint.setServiceEntryPoint(moduleRelativeURL);
    AsyncCallback textCallback = new AsyncCallback() {
      public void onSuccess(Object result) {
        try {        
          String strResult = (String)result;
          // parse, set titleTB, etc also
          ui.getXml().setText(strResult);
          Document d = DocumentHelper.parseText(ui.getXml().getText());
          populateWidgets(d);
          
        } catch (Exception e) {
          e.printStackTrace();
        }
      }

      public void onFailure(Throwable caught) {
        // do some UI stuff to show failure
        ui.getXml().setText("Failed To Load");
      }
    };
  
    service.getActionSequenceXml(actionSequence, textCallback);
    label.setText(actionSequence);

    ui.getSaveButton().addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        	ActionEditorServiceAsync service = (ActionEditorServiceAsync) GWT.create(ActionEditorService.class);
        	ServiceDefTarget endpoint = (ServiceDefTarget) service;
        	String moduleRelativeURL = GWT.getModuleBaseURL() + SERVICE_LOCATION;
        	endpoint.setServiceEntryPoint(moduleRelativeURL);
        	
        	AsyncCallback callback = new AsyncCallback() {
        	    public void onSuccess(Object result) {
                try {
        	    	  Window.alert((String)result);
                } catch (Exception e) {
                  e.printStackTrace();
                }
        	    }

        	    public void onFailure(Throwable caught) {
        	      // do some UI stuff to show failure
        	    	Window.alert("Failed");
        	    }
          };
        	
        	  service.saveActionSequenceXml(actionSequence, ui.getXml().getText(), callback);
      }
    });

    // Assume that the host HTML has elements defined whose
    // IDs are "slot1", "slot2".  In a real app, you probably would not want
    // to hard-code IDs.  Instead, you could, for example, search for all 
    // elements with a particular CSS class and replace them with widgets.
    //

   
    ui.getTabs().addTabListener(new TabListener() {
      public boolean onBeforeTabSelected(SourcesTabEvents sender, int tabIndex) {
        if (tabIndex == 0) { // GENERAL TAB
          if (lastTabIndex == 1) {
            syncFromProcessToXML();
            syncFromXMLToGeneral();
          } else if (lastTabIndex == 2) {
            syncFromXMLToGeneral();
          }
        } else
        if (tabIndex == 1) { // PROCESS TAB
          if (lastTabIndex == 0) {
            syncFromGeneralToXML();
            syncFromXMLToProcess();
          } else if (lastTabIndex == 2) {
            syncFromXMLToProcess();
          }          
        }
        if (tabIndex == 2) { // XML TAB
          if (lastTabIndex == 0) {
            syncFromGeneralToXML();
          } else if (lastTabIndex == 1) {
            syncFromProcessToXML();
          }
        }
        lastTabIndex = tabIndex;
        return true;
      }

      public void onTabSelected(SourcesTabEvents sender, int tabIndex) {
      }
      
    });
    
    ui.getVisible().addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        if (!ui.getVisible().isChecked()) {
          ui.getResultType().setText("none");
        } else {
          ui.getResultType().setText("");
        } 
      }
    });
    
    RootPanel.get("actionUrl").add(label);
    RootPanel.get("main").add(ui.getRoot());
    RootPanel.get("main").setWidth("100%");
    History.addHistoryListener(this);  
  }
	
  private IActionDefinition createActionDefinition(String text) {
    if (text.equals("Relational")) {
      return actionSequenceDocument.addAction(SqlQueryAction.class);
    } else if (text.equals("Pentaho Report")) {
      return actionSequenceDocument.addAction(JFreeReportAction.class);
    } else {
      System.out.println("unsupported at this time: " + text);
      return null;
    }
  }
  
  private IActionPanel createActionPanel(IActionSequenceExecutableStatement action) {
    if (action instanceof SqlQueryAction) {
      return new SqlQueryActionPanel((SqlQueryAction)action, ActionEditor.this);
    } else if (action instanceof JFreeReportAction) {
      return new JFreeReportActionPanel((JFreeReportAction)action, ActionEditor.this);
    } else {
      System.out.println("Unrecognized Action: " + action.toString());
      return null;
    }
  }
  
  public void onHistoryChanged(String historyToken) {
  }
  
  public static String getQueryString() {
    String fullurl = getWindowURL() + "";
    if (fullurl.indexOf('?') >= 0) {
      String queryString = fullurl.substring(fullurl.indexOf('?') + 1);
      return queryString;
    }
    return "";
  }
  
  public static native String getWindowURL() /*-{
  return '' + $wnd.location;
  }-*/;
  
  
  public static String getRequestParameter(String paramName) {
    String queryString = getQueryString();
    int paramIndex = queryString.indexOf(paramName);
    if (paramIndex >= 0) {
      String paramString = queryString.substring(paramIndex);
      int ampIndex = paramString.indexOf('&');
      int eqIndex = paramString.indexOf('=');
      int poundIndex = paramString.indexOf("#");
      if (ampIndex >= 0 && eqIndex >= 0) {
        paramString = paramString.substring(eqIndex + 1, ampIndex);
        return paramString;
      } else if (eqIndex >= 0 && poundIndex == -1) {
        paramString = paramString.substring(eqIndex + 1);
        return paramString;
      } else if (eqIndex >= 0 && poundIndex >= 0) {
        paramString = paramString.substring(eqIndex + 1, poundIndex);
        return paramString;
      }
    }
    return "";
  }
  
}
